/**
 * Copyright 2011, Felix Palmer
 *
 * Licensed under the MIT license:
 * http://creativecommons.org/licenses/MIT/
 */
package com.andatsoft.laisim.activity;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.view.GestureDetectorCompat;
import android.util.Log;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.andatsoft.laisim.R;
import com.andatsoft.laisim.adapter.VisualizerChooserDialogAdapter;
import com.andatsoft.laisim.entity.Song;
import com.andatsoft.laisim.service.PlayerService;
import com.andatsoft.laisim.utils.Common;
import com.andatsoft.laisim.utils.ToastMessage;
import com.andatsoft.laisim.visualizer.VisualizerView;
import com.andatsoft.laisim.visualizer.renderer.CircleBarRenderer;
import com.andatsoft.laisim.visualizer.renderer.CircleRenderer;
import com.andatsoft.laisim.visualizer.renderer.PointLineRenderer;

/**
 * Demo to show how to use VisualizerView
 */
public class VisualizerActivity extends BaseActivity implements
		OnGestureListener {
	public static int systemVolume = 0;

	private VisualizerView mVisualizerView;
	private GestureDetectorCompat mGesture;
	private LinearLayout mLayoutChooser;
	private LinearLayout mLayoutControl;
	private TextView mTvOk;
	private TextView mTvSongTitle;
	private Button mBtnPrev;
	private Button mBtnPlay;
	private Button mBtnNext;

	// Player service
	private PlayerService mPlayerService;
	private boolean mIsBoundService;
	SettingsContentObserver mSettingsContentObserver;
	private ToastMessage mToast;
	private boolean mIsChooserShowing;
	private boolean mIsControlShowing;
	private boolean mCanProcessControl = true;
	private List<Integer> mListVisualizerSelected;
	private boolean mIsRandom;

	private ServiceConnection mPlayerServiceConnection = new ServiceConnection() {

		@Override
		public void onServiceDisconnected(ComponentName name) {
			mPlayerService = null;
		}

		// called when bind service called.
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mPlayerService = ((PlayerService.LocalBinder) service).getService();
			mIsBoundService = true;
			init(mPlayerService.getMediaPlayer());
			Song s = mPlayerService.getCurrentSong();
			if (s == null)
				return;
			mTvSongTitle.setText(s.getTitle() + "-" + s.getArtist());
			if (mPlayerService.isPlaying()) {
				mBtnPlay.setBackgroundResource(R.drawable.btn_notification_pause);
			} else {
				mBtnPlay.setBackgroundResource(R.drawable.btn_notification_play);
			}
		}
	};

	public void doBindService() {
		bindService(new Intent(VisualizerActivity.this, PlayerService.class),
				mPlayerServiceConnection, Context.BIND_AUTO_CREATE);
		// Log.d("Bind", "bind" + bo);
		mIsBoundService = true;
	}

	public void doUnBindService() {
		unbindService(mPlayerServiceConnection);
		mIsBoundService = false;
	}

	private BroadcastReceiver mBroadcastUpdateSongInfo = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			if (mPlayerService == null) {
				return;
			}
			Song s = mPlayerService.getCurrentSong();
			if (s == null)
				return;
			mTvSongTitle.setText(s.getTitle() + "-" + s.getArtist());
		}
	};

	private TextView mTvShortcut;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.activity_visualizer);
		doBindService();
		// get current volume
		AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
		systemVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
		mSettingsContentObserver = new SettingsContentObserver(this,
				new Handler());
		getApplicationContext().getContentResolver().registerContentObserver(
				android.provider.Settings.System.CONTENT_URI, true,
				mSettingsContentObserver);
		mToast = new ToastMessage(getApplicationContext());
		mGesture = new GestureDetectorCompat(getApplicationContext(), this);
		mListVisualizerSelected = new ArrayList<Integer>();
		setupListeners();
		registerReceiver(mBroadcastUpdateSongInfo, new IntentFilter(
				Common.INTENT_UPDATE_SONG_INFO));
	}

	private void init(MediaPlayer mp) {
		// We need to link the visualizer view to the media player so that
		// it displays something
		mVisualizerView = (VisualizerView) findViewById(R.id.visualizerView);
		if (!mVisualizerView.link(mp)) {
			mToast.showLongMessage(getString(R.string.visualizer_toast_not_supported));
			finish();
		}
		// Start with just line renderer
		addSmLineRenderer(false);
		mListVisualizerSelected.add(1);
	}

	private void setupListeners() {
		mLayoutChooser = (LinearLayout) findViewById(R.id.layout_visualizer_chooser);
		mLayoutControl = (LinearLayout) findViewById(R.id.layout_visualizer_control);
		setAlpha(mLayoutControl, 0.5f);
		mBtnPrev = (Button) findViewById(R.id.btn_prev_visualizer);
		mBtnPlay = (Button) findViewById(R.id.btn_play_pause_visualizer);
		mBtnNext = (Button) findViewById(R.id.btn_next_visualizer);

		mTvSongTitle = (TextView) findViewById(R.id.tv_title_visualizer);
		mTvShortcut = (TextView) findViewById(R.id.tv_shortcut_visualizer);

		mBtnPrev.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mPlayerService != null) {
					mPlayerService.playPrevious();
				}
			}
		});

		mBtnNext.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mPlayerService != null) {
					mPlayerService.playNext();
				}
			}
		});

		mBtnPlay.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mPlayerService != null) {
					if (mPlayerService.isPlaying()) {
						mPlayerService.pause(true);
						mBtnPlay.setBackgroundResource(R.drawable.btn_notification_play);
					} else {
						mPlayerService.start();
						mBtnPlay.setBackgroundResource(R.drawable.btn_notification_pause);
					}
				}
			}
		});

		mTvShortcut.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View view, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					setAlpha(view, 0.5f);
					return true;
				case MotionEvent.ACTION_UP:
					setAlpha(view, 1.0f);
					if (!mIsChooserShowing)
						showChooser();
					return true;
				case MotionEvent.ACTION_CANCEL:
					setAlpha(view, 1.0f);
					return true;
				}

				return false;
			}
		});
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		getApplicationContext().getContentResolver().unregisterContentObserver(
				mSettingsContentObserver);
		if (mBroadcastUpdateSongInfo != null)
			unregisterReceiver(mBroadcastUpdateSongInfo);
		if (mIsBoundService)
			doUnBindService();
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (!mIsBoundService)
			doBindService();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// super.onTouchEvent(event);
		return mGesture.onTouchEvent(event);
	}

	// Workaround (for Galaxy S4)
	//
	// "Visualization does not work on the new Galaxy devices"
	// https://github.com/felixpalmer/android-visualizer/issues/5
	//
	// NOTE:
	// This code is not required for visualizing default "test.mp3" file,
	// because tunnel player is used when duration is longer than 1 minute.
	// (default "test.mp3" file: 8 seconds)
	//
	// private void initTunnelPlayerWorkaround() {
	// // Read "tunnel.decode" system property to determine
	// // the workaround is needed
	// if (TunnelPlayerWorkaround.isTunnelDecodeEnabled(this)) {
	// mSilentPlayer = TunnelPlayerWorkaround.createSilentMediaPlayer(this);
	// }
	// }

	// Methods for adding renderers to visualizer

	private void addCircleBarRenderer(boolean combine) {
		Paint paint = new Paint();
		paint.setStrokeWidth(8f);
		paint.setAntiAlias(true);
		paint.setXfermode(new PorterDuffXfermode(Mode.LIGHTEN));
		paint.setColor(Color.argb(255, 222, 92, 143));
		CircleBarRenderer circleBarRenderer = new CircleBarRenderer(paint, 32,
				true);
		if (combine) {
			mVisualizerView.addRenderer(circleBarRenderer);
		} else {
			mVisualizerView.addUniqueRenderer(circleBarRenderer);
		}

	}

	private void addCircleRenderer(boolean combine) {
		Paint paint = new Paint();
		paint.setStrokeWidth(5f);
		paint.setAntiAlias(true);
		paint.setColor(Color.argb(255, 222, 92, 143));
		CircleRenderer circleRenderer = new CircleRenderer(paint, true);
		if (combine) {
			mVisualizerView.addRenderer(circleRenderer);
		} else {
			mVisualizerView.addUniqueRenderer(circleRenderer);
		}
	}

	// private void addLineRenderer(boolean combine) {
	// Paint linePaint = new Paint();
	// linePaint.setStrokeWidth(1f);
	// linePaint.setAntiAlias(true);
	// linePaint.setColor(Color.argb(88, 0, 128, 255));
	//
	// Paint lineFlashPaint = new Paint();
	// lineFlashPaint.setStrokeWidth(5f);
	// lineFlashPaint.setAntiAlias(true);
	// lineFlashPaint.setColor(Color.argb(188, 255, 255, 255));
	// LineRenderer lineRenderer = new LineRenderer(linePaint, lineFlashPaint,
	// true);
	// if (combine) {
	// mVisualizerView.addRenderer(lineRenderer);
	// } else {
	// mVisualizerView.addUniqueRenderer(lineRenderer);
	// }
	// }

	private void addSmLineRenderer(boolean combine) {
		Paint linePaint = new Paint();
		linePaint.setStrokeWidth(3f);
		linePaint.setAntiAlias(true);
		linePaint.setColor(Color.argb(255, 0, 128, 255));

		PointLineRenderer lineRenderer = new PointLineRenderer(linePaint, true);
		if (combine) {
			mVisualizerView.addRenderer(lineRenderer);
		} else {
			mVisualizerView.addUniqueRenderer(lineRenderer);
		}
	}

	public class SettingsContentObserver extends ContentObserver {
		int previousVolume;
		Context context;

		public SettingsContentObserver(Context c, Handler handler) {
			super(handler);
			context = c;

			AudioManager audio = (AudioManager) context
					.getSystemService(Context.AUDIO_SERVICE);
			previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
		}

		@Override
		public boolean deliverSelfNotifications() {
			return super.deliverSelfNotifications();
		}

		@Override
		public void onChange(boolean selfChange) {
			super.onChange(selfChange);

			AudioManager audio = (AudioManager) context
					.getSystemService(Context.AUDIO_SERVICE);
			systemVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
		}
	}

	private void addVisualizer(int index, int combine) {
		if (combine == 1) {
			switch (index) {
			case 1:
				addSmLineRenderer(true);
				break;
			case 2:
				addCircleRenderer(true);
				break;
			case 3:
				addCircleBarRenderer(true);
				break;
			default:
				break;
			}
		} else {
			switch (index) {
			case 1:
				addSmLineRenderer(false);
				break;
			case 2:
				addCircleRenderer(false);
				break;
			case 3:
				addCircleBarRenderer(false);
				break;
			default:
				break;
			}

		}
	}

	private Runnable mUpdateVis = new Runnable() {

		@Override
		public void run() {
			mVisualizerView.clearRenderers();
			int ranIndex = new Random().nextInt(mListVisualizerSelected.size());
			if (mListVisualizerSelected.get(ranIndex) == 0) {
				mHandler.removeCallbacks(mUpdateVis);
				mHandler.postDelayed(mUpdateVis, 2000);
			} else {
				addVisualizer(mListVisualizerSelected.get(ranIndex), 0);
			}
			Log.e("ranind",
					"" + ranIndex + "," + mListVisualizerSelected.get(ranIndex));
			for (Integer i : mListVisualizerSelected) {
				if (!i.equals(ranIndex)) {
					int combine = new Random().nextInt(5);
					if (combine == 1)
						addVisualizer(i, 1);
				}
			}
			mHandler.postDelayed(mUpdateVis, 15000);
		}
	};

	private String[] builtInChooser = new String[] { "Random", "Point Line",
			"Circle", "Circle Bar" };
	private Handler mHandler = new Handler();

	private void showChooser() {
		mLayoutChooser.removeAllViews();
		mLayoutChooser.setVisibility(View.VISIBLE);
		getLayoutInflater().inflate(R.layout.dialog_visualizer_chooser,
				mLayoutChooser, true);
		final ListView listView = ((ListView) findViewById(R.id.list_visualizer_dialog));
		listView.setAdapter(new VisualizerChooserDialogAdapter(
				getApplicationContext(), builtInChooser,
				mListVisualizerSelected));
		listView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
					long arg3) {
				if (pos == 0) {
					if (builtInChooser.length == mListVisualizerSelected.size()) {
						mListVisualizerSelected.clear();
						mIsRandom = false;
					} else {
						mIsRandom = true;
						if (mListVisualizerSelected.size() > 0) {
							if (!mListVisualizerSelected.contains(pos)) {
								mListVisualizerSelected.add(pos);
								mIsRandom = true;
							} else {
								mListVisualizerSelected.remove((Integer) pos);
								mIsRandom = false;
							}
						} else {
							for (int i = 0; i < builtInChooser.length; i++) {
								if (!mListVisualizerSelected.contains(i))
									mListVisualizerSelected.add(i);
							}
						}
					}
				} else {
					if (!mListVisualizerSelected.contains(pos)) {
						mListVisualizerSelected.add(pos);
						// if (pos == 0)

					} else {
						mListVisualizerSelected.remove((Integer) pos);
						// if (pos == 0)

					}
				}
				// mIndexSelected = pos;
				((VisualizerChooserDialogAdapter) listView.getAdapter())
						.setItemsSelected(mListVisualizerSelected);

			}
		});
		mTvOk = (TextView) findViewById(R.id.tv_visualizer_dialog_ok);
		mTvOk.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					setAlpha(v, 0.5f);
					return true;
				case MotionEvent.ACTION_UP:
					setAlpha(v, 1.0f);
					dismissChooser();
					mVisualizerView.clearRenderers();
					if (mIsRandom) {
						mHandler.post(mUpdateVis);
					} else {
						mHandler.removeCallbacks(mUpdateVis);
						for (Integer i : mListVisualizerSelected) {
							addVisualizer(i, 1);
						}
					}
					return true;
				}
				return false;
			}
		});
		Animation animation = AnimationUtils.loadAnimation(getBaseContext(),
				R.anim.message_box_slide_top_to_bottom_fade_in);
		animation.setStartOffset(0);
		mLayoutChooser.startAnimation(animation);
		mIsChooserShowing = true;

	}

	@Override
	public boolean onDown(MotionEvent e) {

		return false;
	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {

		return false;
	}

	@Override
	public void onLongPress(MotionEvent e) {

	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		// float y1 = e1.getY();
		// float y2 = e2.getY();
		// if (y2 - y1 > 50) {
		// Log.d("Vidssss", "SHow chioioo");
		// showChooser();
		// }
		return false;
	}

	@Override
	public void onShowPress(MotionEvent e) {

	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		Log.e("Vidssss", "SHow single");
		if (mCanProcessControl) {
			if (mIsControlShowing) {
				hideControl();
			} else {
				showControl();
			}
		}
		return false;
	}

	private void showControl() {
		mCanProcessControl = false;
		mLayoutControl.setVisibility(View.VISIBLE);
		Animation animation = AnimationUtils.loadAnimation(getBaseContext(),
				R.anim.slide_bottom_to_top_fade_in);
		animation.setStartOffset(0);
		animation.setDuration(350);
		animation.setAnimationListener(new AnimationListener() {

			@Override
			public void onAnimationStart(Animation arg0) {

			}

			@Override
			public void onAnimationRepeat(Animation arg0) {

			}

			@Override
			public void onAnimationEnd(Animation arg0) {
				mIsControlShowing = true;
				mCanProcessControl = true;
			}
		});

		mLayoutControl.startAnimation(animation);
	}

	private void hideControl() {
		mCanProcessControl = false;
		Animation animation = AnimationUtils.loadAnimation(getBaseContext(),
				R.anim.slide_top_to_bottom_fade_out);
		animation.setStartOffset(0);
		animation.setDuration(500);
		animation.setAnimationListener(new AnimationListener() {

			@Override
			public void onAnimationStart(Animation arg0) {

			}

			@Override
			public void onAnimationRepeat(Animation arg0) {

			}

			@Override
			public void onAnimationEnd(Animation arg0) {
				mLayoutControl.setVisibility(View.INVISIBLE);
				mIsControlShowing = false;
				mCanProcessControl = true;
			}
		});
		mLayoutControl.startAnimation(animation);
	}

	private void dismissChooser() {
		Animation animation = AnimationUtils.loadAnimation(getBaseContext(),
				R.anim.message_box_slide_bottom_to_top_fade_out);
		animation.setStartOffset(0);
		animation.setAnimationListener(new AnimationListener() {

			@Override
			public void onAnimationStart(Animation arg0) {

			}

			@Override
			public void onAnimationRepeat(Animation arg0) {

			}

			@Override
			public void onAnimationEnd(Animation arg0) {
				unbindDrawables(mLayoutChooser);
				mLayoutChooser.setVisibility(View.GONE);
				mIsChooserShowing = false;
			}
		});
		mLayoutChooser.startAnimation(animation);

	}

	@Override
	public void onBackPressed() {
		if (mIsChooserShowing) {
			dismissChooser();
		} else if (mIsControlShowing) {
			hideControl();
		} else {
			super.onBackPressed();
		}
	}

}